#include <stdlib.h>
#include "Arbre.h"
#include "Symbole.h"
#include "SymboleValue.h"
#include "LecteurFonction.h"

////////////////////////////////////////////////////////////////////////////////
// NoeudSeqInst
////////////////////////////////////////////////////////////////////////////////

NoeudSeqInst::NoeudSeqInst() : tabInst() { }

////////////////////////////////////////////////////////////////////////////////

Valeur* NoeudSeqInst::getValeur() {
    Valeur* valeur = NULL;
    for (unsigned int i = 0; i < tabInst.size(); i++)
        valeur = tabInst[i]->getValeur(); // on evalue chaque instruction de la séquence
    return valeur; // par convention, resultat = valeur de la derniere instruction
}

////////////////////////////////////////////////////////////////////////////////

void NoeudSeqInst::afficher(unsigned short indentation) {
    Noeud::afficher(indentation);
    cout << "Noeud - Sequence de " << tabInst.size() << " instruction(s)" << endl;
    for (unsigned int i = 0; i < tabInst.size(); i++)
        tabInst[i]->afficher(indentation + 1); // on affiche les fils en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////

void NoeudSeqInst::ajouteInstruction(Noeud* instruction) {
    tabInst.push_back(instruction);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudAffectation
////////////////////////////////////////////////////////////////////////////////

NoeudAffectation::NoeudAffectation(Noeud* variable, Noeud* expression) {
    this->variable = variable;
    this->expression = expression;
}

////////////////////////////////////////////////////////////////////////////////

Valeur* NoeudAffectation::getValeur() {
    Valeur* valeur = expression->getValeur(); // on évalue l'expression
    ((SymboleValue*) variable)->setValeur(valeur); // on affecte la variable
    return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////

void NoeudAffectation::afficher(unsigned short indentation) {
    Noeud::afficher(indentation);
    cout << "Noeud - Affectation" << endl;
    variable->afficher(indentation + 1); // on affiche variable et expression
    expression->afficher(indentation + 1); // en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
// NoeudOperateurBinaire
////////////////////////////////////////////////////////////////////////////////

NoeudOperateurBinaire::NoeudOperateurBinaire(Symbole operateur,
        Noeud* operandeGauche,
        Noeud* operandeDroit) {
    this->operateur = operateur;
    this->operandeGauche = operandeGauche;
    this->operandeDroit = operandeDroit;
}

////////////////////////////////////////////////////////////////////////////////

Valeur* NoeudOperateurBinaire::getValeur() {
    Valeur* valeur = NULL;
    Valeur* od = operandeDroit->getValeur();
    if (this->operateur == "-" && operandeGauche == NULL) {
        if (od->estEntiere()) {
            valeur = new ValeurEntiere(-((dynamic_cast<ValeurEntiere*> (od))->getValeur()));
        } else if (od->estReelle()) {
            valeur = new ValeurReelle(-((dynamic_cast<ValeurReelle*> (od))->getValeur()));
        } else {
            cout << "Erreur pendant l'interpretation : utilisation incorrecte du \"-\"" << endl;
            exit(0); // plus tard on levera une exception
        }
    } else if (this->operateur == "non") {
        if (od->estEntiere()) {
            valeur = new ValeurEntiere(!((dynamic_cast<ValeurEntiere*> (od))->getValeur()));
        } else {
            cout << "Erreur pendant l'interpretation : utilisation incorrecte du \"non\"" << endl;
            exit(0); // plus tard on levera une exception
        }
    } else {
        Valeur* og = operandeGauche->getValeur();
        if (this->operateur == "+") {
            if (og->estEntiere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() + (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurEntiere*> (og))->getValeur() + (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() + (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                } else {
                    cout << "Erreur pendant l'interpretation : utilisation incorrecte du \"+\"" << endl;
                    exit(0); // plus tard on levera une exception
                }
            } else if (og->estReelle()) {
                if (od->estEntiere()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurReelle*> (og))->getValeur() + (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurReelle*> (og))->getValeur() + (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurReelle*> (og))->getValeur() + (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                } else {
                    cout << "Erreur pendant l'interpretation : utilisation incorrecte du \"+\"" << endl;
                    exit(0); // plus tard on levera une exception
                }
            } else if (og->estChaine()) {
                if (od->estChaine()) {
                    // Manip pour concaténer les chaines sans laiser le "'" du milieu
                    string chaine1 = (dynamic_cast<ValeurChaine*> (og))->getValeur();
                    chaine1 = chaine1.substr(1, chaine1.length() - 2);
                    string chaine2 = (dynamic_cast<ValeurChaine*> (od))->getValeur();
                    chaine2 = chaine2.substr(1, chaine2.length() - 2);
                    string chaineFinale = '"' + chaine1 + chaine2 + '"';
                    valeur = new ValeurChaine(chaineFinale);
                } else if (od->estCaractere()) {
                    // Manip pour concaténer les chaines sans laiser le "'" du milieu
                    string chaine1 = (dynamic_cast<ValeurChaine*> (og))->getValeur();
                    chaine1 = chaine1.substr(1, chaine1.length() - 2);
                    string chaine2 = (dynamic_cast<ValeurCaractere*> (od))->getValeur();
                    chaine2 = chaine2.substr(1, chaine2.length() - 2);
                    string chaineFinale = '"' + chaine1 + chaine2 + '"';
                    valeur = new ValeurChaine(chaineFinale);
                } else {
                    cout << "Erreur pendant l'interpretation : utilisation incorrecte du \"+\"" << endl;
                    exit(0); // plus tard on levera une exception
                }
            } else if (og->estCaractere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] + (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] + (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estChaine()) {
                    // Manip pour concaténer les chaines sans laiser le "' du milieu
                    string chaine1 = (dynamic_cast<ValeurCaractere*> (og))->getValeur();
                    chaine1 = chaine1.substr(1, chaine1.length() - 2);
                    string chaine2 = (dynamic_cast<ValeurChaine*> (od))->getValeur();
                    chaine2 = chaine2.substr(1, chaine2.length() - 2);
                    string chaineFinale = '"' + chaine1 + chaine2 + '"';
                    valeur = new ValeurChaine(chaineFinale);
                } else if (od->estCaractere()) {
                    valeur = new ValeurCaractere((dynamic_cast<ValeurCaractere*> (og))->getValeur() + (dynamic_cast<ValeurCaractere*> (od))->getValeur());
                }
            }
        } else if (this->operateur == "-") {
            if (og->estChaine() || od->estChaine()) {
                cout << "Erreur pendant l'interpretation : opérateur \"-\" sur chaine" << endl;
                exit(0); // plus tard on levera une exception
            } else if (og->estEntiere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() - (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurEntiere*> (og))->getValeur() - (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() - (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                }
            } else if (og->estReelle()) {
                if (od->estEntiere()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurReelle*> (og))->getValeur() - (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurReelle*> (og))->getValeur() - (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurReelle*> (og))->getValeur() - (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                }
            } else if (og->estCaractere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] - (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] - (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] - (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                }
            }
        } else if (this->operateur == "*") {
            if (!og->estNumerique() || !od->estNumerique()) {
                cout << "Erreur pendant l'interpretation : multiplication de termes non numériques" << endl;
                exit(0); // plus tard on levera une exception
            } else if (og->estEntiere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() * (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurEntiere*> (og))->getValeur() * (dynamic_cast<ValeurReelle*> (od))->getValeur());
                }
            } else if (og->estReelle()) {
                if (od->estEntiere()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurReelle*> (og))->getValeur() * (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurReelle((dynamic_cast<ValeurReelle*> (og))->getValeur() * (dynamic_cast<ValeurReelle*> (od))->getValeur());
                }
            }
        } else if (this->operateur == "/") {
            if (!og->estNumerique() || !od->estNumerique()) {
                cout << "Erreur pendant l'interpretation : division de termes non numériques" << endl;
                exit(0); // plus tard on levera une exception
            } else if (og->estEntiere()) {
                if (od->estEntiere()) {
                    if ((dynamic_cast<ValeurEntiere*> (od))->getValeur() == 0) {
                        cout << "Erreur pendant l'interpretation : division par zero" << endl;
                        exit(0); // plus tard on levera une exception
                    } else {
                        valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() / (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                    }
                } else if (od->estReelle()) {
                    if ((dynamic_cast<ValeurReelle*> (od))->getValeur() == 0.0) {
                        cout << "Erreur pendant l'interpretation : division par zero" << endl;
                        exit(0); // plus tard on levera une exception
                    } else {
                        valeur = new ValeurReelle((dynamic_cast<ValeurEntiere*> (og))->getValeur() / (dynamic_cast<ValeurReelle*> (od))->getValeur());
                    }
                }
            } else if (og->estReelle()) {
                if (od->estEntiere()) {
                    if ((dynamic_cast<ValeurEntiere*> (od))->getValeur() == 0) {
                        cout << "Erreur pendant l'interpretation : division par zero" << endl;
                        exit(0); // plus tard on levera une exception
                    } else {
                        valeur = new ValeurReelle((dynamic_cast<ValeurReelle*> (og))->getValeur() / (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                    }
                } else if (od->estReelle()) {
                    if ((dynamic_cast<ValeurReelle*> (od))->getValeur() == 0.0) {
                        cout << "Erreur pendant l'interpretation : division par zero" << endl;
                        exit(0); // plus tard on levera une exception
                    } else {
                        valeur = new ValeurReelle((dynamic_cast<ValeurReelle*> (og))->getValeur() / (dynamic_cast<ValeurReelle*> (od))->getValeur());
                    }
                }
            }
        } else if (this->operateur == "ou") {
            if (og->estEntiere() && od->estEntiere()) {
                valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() || (dynamic_cast<ValeurEntiere*> (od))->getValeur());
            } else {
                cout << "Erreur pendant l'interpretation : opérateur \"ou\" sur valeur de type incorrect" << endl;
                exit(0); // plus tard on levera une exception
            }
        } else if (this->operateur == "et") {
            if (og->estEntiere() && od->estEntiere()) {
                valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() && (dynamic_cast<ValeurEntiere*> (od))->getValeur());
            } else {
                cout << "Erreur pendant l'interpretation : opérateur \"et\" sur valeur de type incorrect" << endl;
                exit(0); // plus tard on levera une exception
            }
        } else if (this->operateur == "==") {
            if (og->estEntiere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() == (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() == (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() == (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                } else {
                    cout << "Erreur pendant l'interpretation : opérateur \"==\" sur valeur de type incorrect" << endl;
                    exit(0); // plus tard on levera une exception
                }
            } else if (og->estReelle()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() == (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() == (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() == (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                } else {
                    cout << "Erreur pendant l'interpretation : opérateur \"==\" sur valeur de type incorrect" << endl;
                    exit(0); // plus tard on levera une exception
                }
            } else if (og->estChaine()) {
                if (od->estChaine()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurChaine*> (og))->getValeur().compare((dynamic_cast<ValeurChaine*> (od))->getValeur()));
                } else if (od->estCaractere()) {
                    string c = ((dynamic_cast<ValeurCaractere*> (od))->getValeur());
                    valeur = new ValeurEntiere((dynamic_cast<ValeurChaine*> (og))->getValeur().substr(1, (dynamic_cast<ValeurChaine*> (og))->getValeur().length() - 1).compare(&c[1]));
                } else {
                    cout << "Erreur pendant l'interpretation : opérateur \"==\" sur valeur de type incorrect" << endl;
                    exit(0); // plus tard on levera une exception
                }
            } else if (og->estCaractere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] == (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] == (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estChaine()) {
                    string c = ((dynamic_cast<ValeurCaractere*> (og))->getValeur());
                    valeur = new ValeurEntiere((dynamic_cast<ValeurChaine*> (od))->getValeur().substr(1, (dynamic_cast<ValeurChaine*> (od))->getValeur().length() - 1).compare(&c[1]));
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur() == (dynamic_cast<ValeurCaractere*> (od))->getValeur());
                }
            }
        } else if (this->operateur == "!=") {
            if (og->estEntiere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() != (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() != (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() != (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                } else {
                    cout << "Erreur pendant l'interpretation : opérateur \"!=\" sur valeur de type incorrect" << endl;
                    exit(0); // plus tard on levera une exception
                }
            } else if (og->estReelle()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() != (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() != (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() != (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                } else {
                    cout << "Erreur pendant l'interpretation : opérateur \"!=\" sur valeur de type incorrect" << endl;
                    exit(0); // plus tard on levera une exception
                }
            } else if (og->estChaine()) {
                if (od->estChaine()) {
                    valeur = new ValeurEntiere(!((dynamic_cast<ValeurChaine*> (og))->getValeur().compare((dynamic_cast<ValeurChaine*> (od))->getValeur())));
                } else if (od->estCaractere()) {
                    string c = ((dynamic_cast<ValeurCaractere*> (od))->getValeur());
                    valeur = new ValeurEntiere((dynamic_cast<ValeurChaine*> (og))->getValeur().substr(1, (dynamic_cast<ValeurChaine*> (og))->getValeur().length() - 1).compare(&c[1]));
                } else {
                    cout << "Erreur pendant l'interpretation : opérateur \"!=\" sur valeur de type incorrect" << endl;
                    exit(0); // plus tard on levera une exception
                }
            } else if (og->estCaractere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] != (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] != (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estChaine()) {
                    string c = ((dynamic_cast<ValeurCaractere*> (og))->getValeur());
                    valeur = new ValeurEntiere((dynamic_cast<ValeurChaine*> (od))->getValeur().substr(1, (dynamic_cast<ValeurChaine*> (od))->getValeur().length() - 1).compare(&c[1]));
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur() != (dynamic_cast<ValeurCaractere*> (od))->getValeur());
                }
            }
        } else if (this->operateur == ">") {
            if (og->estChaine() || od->estChaine()) {
                cout << "Erreur pendant l'interpretation : opérateur \">\" sur chaine" << endl;
                exit(0); // plus tard on levera une exception
            } else if (og->estEntiere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() > (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() > (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() > (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                }
            } else if (og->estReelle()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() > (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() > (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() > (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                }
            } else if (og->estCaractere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] > (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] > (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur() > (dynamic_cast<ValeurCaractere*> (od))->getValeur());
                }
            }
        } else if (this->operateur == ">=") {
            if (og->estChaine() || od->estChaine()) {
                cout << "Erreur pendant l'interpretation : opérateur \">=\" sur chaine" << endl;
                exit(0); // plus tard on levera une exception
            } else if (og->estEntiere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() >= (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() >= (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() >= (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                }
            } else if (og->estReelle()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() >= (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() >= (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() >= (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                }
            } else if (og->estCaractere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] >= (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] >= (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur() >= (dynamic_cast<ValeurCaractere*> (od))->getValeur());
                }
            }
        } else if (this->operateur == "<") {
            if (og->estChaine() || od->estChaine()) {
                cout << "Erreur pendant l'interpretation : opérateur \"<\" sur chaine" << endl;
                exit(0); // plus tard on levera une exception
            } else if (og->estEntiere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() < (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() < (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() < (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                }
            } else if (og->estReelle()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() < (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() < (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() < (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                }
            } else if (og->estCaractere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] < (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] < (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur() < (dynamic_cast<ValeurCaractere*> (od))->getValeur());
                }
            }
        } else if (this->operateur == "<=") {
            if (og->estChaine() || od->estChaine()) {
                cout << "Erreur pendant l'interpretation : opérateur \"<=\" sur chaine" << endl;
                exit(0); // plus tard on levera une exception
            } else if (og->estEntiere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() <= (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() <= (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurEntiere*> (og))->getValeur() <= (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                }
            } else if (og->estReelle()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() <= (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() <= (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurReelle*> (og))->getValeur() <= (dynamic_cast<ValeurCaractere*> (od))->getValeur().c_str()[1]);
                }
            } else if (og->estCaractere()) {
                if (od->estEntiere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] <= (dynamic_cast<ValeurEntiere*> (od))->getValeur());
                } else if (od->estReelle()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur().c_str()[1] <= (dynamic_cast<ValeurReelle*> (od))->getValeur());
                } else if (od->estCaractere()) {
                    valeur = new ValeurEntiere((dynamic_cast<ValeurCaractere*> (og))->getValeur() <= (dynamic_cast<ValeurCaractere*> (od))->getValeur());
                }
            }
        }
    }
    return valeur;
}

////////////////////////////////////////////////////////////////////////////////

void NoeudOperateurBinaire::afficher(unsigned short indentation) {
    Noeud::afficher(indentation);
    cout << "Noeud - Operateur Binaire \"" << this->operateur.getChaine() << "\" applique a : " << endl;
    operandeGauche->afficher(indentation + 1); // on affiche fils gauche et fils droit
    operandeDroit->afficher(indentation + 1); // en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstCommutation
////////////////////////////////////////////////////////////////////////////////

NoeudInstCommutation::NoeudInstCommutation() : conds(), seqInsts() {}

////////////////////////////////////////////////////////////////////////////////

void NoeudInstCommutation::ajouterCas(Noeud* cond, Noeud * seqInst) {
    this->conds.push_back(cond);
    this->seqInsts.push_back(seqInst);
}


////////////////////////////////////////////////////////////////////////////////
// NoeudInstSi
////////////////////////////////////////////////////////////////////////////////

NoeudInstSi::NoeudInstSi(Noeud* condSi, Noeud * seqInstSi) : NoeudInstCommutation() {
    this->conds.push_back(condSi);
    this->seqInsts.push_back(seqInstSi);
}

////////////////////////////////////////////////////////////////////////////////

Valeur * NoeudInstSi::getValeur() {
    bool fini = false;
    vector<Noeud*>::iterator itCond, itSeqInst;
    itCond = conds.begin();
    itSeqInst = seqInsts.begin();
    while (itCond != conds.end() && itSeqInst != seqInsts.end() && !fini) {
        if ((*itCond)==NULL) {
            (*itSeqInst)->getValeur();
            fini = true;
        } else if (((ValeurEntiere*)(*itCond)->getValeur())->getValeur()) {
            (*itSeqInst)->getValeur();
            fini = true;
        } else {
            itCond++;
            itSeqInst++;
        }
    }
    return new ValeurEntiere(!fini); // par convention, on renvoie 0 si on a executé une seqInst, 1 sinon
}

////////////////////////////////////////////////////////////////////////////////

void NoeudInstSi::afficher(unsigned short indentation) {
    Noeud::afficher(indentation);
    cout << "Noeud - Instruction si" << endl;
    vector<Noeud*>::iterator itCond, itSeqInst;
    itCond = conds.begin();
    itSeqInst = seqInsts.begin();
    while (itCond != conds.end() && itSeqInst != seqInsts.end()) {
        if (*itCond!=NULL) {
            (*itCond)->afficher(indentation + 1);
        }
        (*itSeqInst)->afficher(indentation + 1);
        itCond++;
        itSeqInst++;
    }
}


////////////////////////////////////////////////////////////////////////////////
// NoeudInstChoix
////////////////////////////////////////////////////////////////////////////////

NoeudInstChoix::NoeudInstChoix() : NoeudInstCommutation() {
}

////////////////////////////////////////////////////////////////////////////////

Valeur * NoeudInstChoix::getValeur() {
    bool fini = false;
    vector<Noeud*>::iterator itCond, itSeqInst;
    itCond = conds.begin();
    itSeqInst = seqInsts.begin();
    while (itCond != conds.end() && itSeqInst != seqInsts.end() && !fini) {
        if (*itCond==NULL) {
            (*itSeqInst)->getValeur();
            fini = true;
        } else if ((*itCond)->getValeur()) {
            (*itSeqInst)->getValeur();
            fini = true;
        } else {
            itCond++;
            itSeqInst++;
        }
    }
    return new ValeurEntiere(!fini); // par convention, on renvoie 0 si on a executé une seqInst, 1 sinon
}

////////////////////////////////////////////////////////////////////////////////

void NoeudInstChoix::afficher(unsigned short indentation) {
    Noeud::afficher(indentation);
    cout << "Noeud - Instruction choix" << endl;
    vector<Noeud*>::iterator itCond, itSeqInst;
    itCond = conds.begin();
    itSeqInst = seqInsts.begin();
    while (itCond != conds.end() && itSeqInst != seqInsts.end()) {
        if (*itCond!=NULL) {
            (*itCond)->afficher(indentation + 1);
        }
        (*itSeqInst)->afficher(indentation + 1);
        itCond++;
        itSeqInst++;
    }
}

////////////////////////////////////////////////////////////////////////////////
// NoeudBoucle
////////////////////////////////////////////////////////////////////////////////

NoeudBoucle::NoeudBoucle(Noeud* cond, Noeud * seqInst) {
    this->cond = cond;
    this->seqInst = seqInst;
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstTq
////////////////////////////////////////////////////////////////////////////////

NoeudInstTq::NoeudInstTq(Noeud* cond, Noeud * seqInst) : NoeudBoucle(cond, seqInst) { }

////////////////////////////////////////////////////////////////////////////////

Valeur * NoeudInstTq::getValeur() {
    int nb = 0;
    //while ((this->getCond())->getValeur()) {
    this->getSeqInst()->getValeur();
    nb++;
    //}
    return new ValeurEntiere(nb); // par convention, on renvoie le nombre de passage dans la boucle
}

////////////////////////////////////////////////////////////////////////////////

void NoeudInstTq::afficher(unsigned short indentation) {
    Noeud::afficher(indentation);
    cout << "Noeud - Instruction Tantque" << endl;
    this->getCond()->afficher(indentation + 1);
    this->getSeqInst()->afficher(indentation + 1);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstRepeter
////////////////////////////////////////////////////////////////////////////////

NoeudInstRepeter::NoeudInstRepeter(Noeud* cond, Noeud * seqInst) : NoeudBoucle(cond, seqInst) { }

////////////////////////////////////////////////////////////////////////////////

Valeur * NoeudInstRepeter::getValeur() {
    int nb = 0;
    do {
        this->getSeqInst()->getValeur();
        nb++;
    } while (!(this->getCond())->getValeur());
    return new ValeurEntiere(nb); // par convention, on renvoie le nombre de passage dans la boucle
}

////////////////////////////////////////////////////////////////////////////////

void NoeudInstRepeter::afficher(unsigned short indentation) {
    Noeud::afficher(indentation);
    cout << "Noeud - Instruction Repeter" << endl;
    this->getSeqInst()->afficher(indentation + 1);
    this->getCond()->afficher(indentation + 1);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstPour
////////////////////////////////////////////////////////////////////////////////

NoeudInstPour::NoeudInstPour(Noeud* aff1, Noeud* cond, Noeud* aff2, Noeud * seqInst) : NoeudBoucle(cond, seqInst) {
    this->aff1 = aff1;
    this->aff2 = aff2;
}

////////////////////////////////////////////////////////////////////////////////

Valeur * NoeudInstPour::getValeur() {
    int nb = 0;
    if (!this->aff1->getValeur()->estNumerique() || !this->aff2->getValeur()->estNumerique() || this->aff1->getValeur()->estReelle() || this->aff2->getValeur()->estReelle()) {
        cout << "Erreur pendant l'interpretation : boucle for doit avoir var entiere" << endl;
        exit(0); // plus tard on levera une exception
    } else {
        for (int i = (dynamic_cast<ValeurEntiere*> (this->aff1))->getValeur(); this->getCond()->getValeur(); i = (dynamic_cast<ValeurEntiere*> (this->aff2))->getValeur()) {
            this->getSeqInst()->getValeur();
            nb++;
        }
    }
    return new ValeurEntiere(nb); // par convention, on renvoie le nombre de passage dans la boucle
}

////////////////////////////////////////////////////////////////////////////////

void NoeudInstPour::afficher(unsigned short indentation) {
    Noeud::afficher(indentation);
    cout << "Noeud - Instruction Pour" << endl;
    this->aff1->afficher(indentation + 1);
    this->getCond()->afficher(indentation + 1);
    this->aff2->afficher(indentation + 1);
    this->getSeqInst()->afficher(indentation + 1);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstLire
////////////////////////////////////////////////////////////////////////////////

NoeudInstLire::NoeudInstLire(Noeud * variable) {
    this->variable = variable;
}

////////////////////////////////////////////////////////////////////////////////

Valeur * NoeudInstLire::getValeur() {
    string val;
    cin >> val;
    cin.ignore(256, '\n');
    SymboleValue* s = new SymboleValue(val);
    ((SymboleValue*) variable)->setValeur(s->getValeur());
    //delete(s);
    return this->variable->getValeur();
}

////////////////////////////////////////////////////////////////////////////////

void NoeudInstLire::afficher(unsigned short indentation) {
    Noeud::afficher(indentation);
    cout << "Noeud - Instruction Lire" << endl;
    this->variable->afficher(indentation + 1);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstEcrire
////////////////////////////////////////////////////////////////////////////////

NoeudInstEcrire::NoeudInstEcrire(Noeud * argument) {
    this->argument = argument;
}

////////////////////////////////////////////////////////////////////////////////

Valeur * NoeudInstEcrire::getValeur() {
    SymboleValue symb = *(SymboleValue*) argument;
    Valeur* valeur = symb.getValeur();
    if (valeur->estEntiere()) {
        cout << (dynamic_cast<ValeurEntiere*> (valeur))->getValeur();
    } else if (valeur->estReelle()) {
        cout << (dynamic_cast<ValeurReelle*> (valeur))->getValeur();
    } else if (valeur->estCaractere()) {
        // On récupère le "vrai" caractère de la chaine représentant un caractère :
        //      - On enleve les '
        //      - On remplace les potentiels chaines \x par le caractère '\x' correspondant
        const char* chaineCaractere = (dynamic_cast<ValeurCaractere*> (valeur))->getValeur().c_str();
        char c = chaineCaractere[1];
        if (c == '\\') {
            char d = chaineCaractere[2];
            if (d == 'n') {
                c = '\n';
            } else if (d == 'r') {
                c = '\r';
            } else if (d == 't') {
                c = '\t';
            }
        }
        cout << c;
    } else if (valeur->estChaine()) {
        // On va transformer cette chaine en "vraie" chaine :
        //      - On enleve les " du début et de la fin
        //      - On remplace les \x par les vrais caractères '\x'

        // On prend la taille de la chaine privée de ces "
        int taille = (dynamic_cast<ValeurChaine*> (valeur))->getValeur().length() - 2;
        // On mets la chaine privée de ces " dans un tableau de char
        const char* tmp = (dynamic_cast<ValeurChaine*> (valeur))->getValeur().substr(1, (dynamic_cast<ValeurChaine*> (valeur))->getValeur().length() - 1).c_str();
        // On crée le vecteur qui contiendra la nouvelle chaine
        vector<char>* tmp2 = new vector<char>();
        // On parcourt le tableau de char en retirant les \ et en remplacant les caractères qui les suivent
        //  par les caractères '\x' correspondant
        for (int i = 0; i < taille; i++) {
            if (tmp[i] != '\\') {
                tmp2->push_back(tmp[i]);
            } else if (i < taille) {
                i++;
                if (tmp[i] == 'n') {
                    tmp2->push_back('\n');
                } else if (tmp[i] == 'r') {
                    tmp2->push_back('\r');
                } else if (tmp[i] == 't') {
                    tmp2->push_back('\t');
                }
            }
        }
        // On retransforme ce vecteur en un objet de la classe string
        string* tmp3 = new string();
        vector<char>::iterator i;
        for (i = tmp2->begin(); i != tmp2->end(); i++) {
            tmp3->append(1, (*i));
        }
        // On affiche enfin cette chaine
        cout << *tmp3;
    }
    return this->argument->getValeur();
}

////////////////////////////////////////////////////////////////////////////////

void NoeudInstEcrire::afficher(unsigned short indentation) {
    Noeud::afficher(indentation);
    cout << "Noeud - Instruction Ecrire" << endl;
    this->argument->afficher(indentation + 1);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudAppelFonction
////////////////////////////////////////////////////////////////////////////////

NoeudAppelFonction::NoeudAppelFonction(string nom, vector<Noeud*> parametres, vector<LecteurFonction*>* tf) : parametres(parametres) {
    this->nom = nom;
    this->tf = tf;
}

////////////////////////////////////////////////////////////////////////////////

Valeur * NoeudAppelFonction::getValeur() {
    stack<Valeur*> pile;
    vector<Noeud*>::iterator itNoeud;
    for (itNoeud = this->parametres.begin(); itNoeud != this->parametres.end(); itNoeud++) {
        pile.push((*itNoeud)->getValeur());
    }
    vector<LecteurFonction*>::iterator itFonc = tf->begin();
    bool trouve = false;
    while (!trouve && itFonc != tf->end()) {
        if (*(*itFonc) == this->nom) {
            trouve = true;
        }
    }
    if (trouve) {
        return (*itFonc)->getValeur(pile);
    } else {
        cout << "Erreur : fonction " << this->nom << " non déclarée" << endl;
        exit(0);
    }
}

////////////////////////////////////////////////////////////////////////////////

void NoeudAppelFonction::afficher(unsigned short indentation) {
    Noeud::afficher(indentation);
    cout << "Noeud - Appel de fonction" << endl;
    cout << setw(4 * (indentation + 1)) << " " << "Feuille - Nom : " << this->nom << endl;
    vector<Noeud*>::iterator it;
    for (it = this->parametres.begin(); it != this->parametres.end(); it++) {
        (*it)->afficher(indentation + 1);
    }
}
